home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / snd_win.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  18.6 KB  |  862 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include <float.h>
  21.  
  22. #include "../client/client.h"
  23. #include "../client/snd_loc.h"
  24. #include "winquake.h"
  25.  
  26. #define iDirectSoundCreate(a,b,c)    pDirectSoundCreate(a,b,c)
  27.  
  28. HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
  29.  
  30. // 64K is > 1 second at 16-bit, 22050 Hz
  31. #define    WAV_BUFFERS                64
  32. #define    WAV_MASK                0x3F
  33. #define    WAV_BUFFER_SIZE            0x0400
  34. #define SECONDARY_BUFFER_SIZE    0x10000
  35.  
  36. typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;
  37.  
  38. cvar_t    *s_wavonly;
  39.  
  40. static qboolean    dsound_init;
  41. static qboolean    wav_init;
  42. static qboolean    snd_firsttime = true, snd_isdirect, snd_iswave;
  43. static qboolean    primary_format_set;
  44.  
  45. // starts at 0 for disabled
  46. static int    snd_buffer_count = 0;
  47. static int    sample16;
  48. static int    snd_sent, snd_completed;
  49.  
  50. /* 
  51.  * Global variables. Must be visible to window-procedure function 
  52.  *  so it can unlock and free the data block after it has been played. 
  53.  */ 
  54.  
  55.  
  56. HANDLE        hData;
  57. HPSTR        lpData, lpData2;
  58.  
  59. HGLOBAL        hWaveHdr;
  60. LPWAVEHDR    lpWaveHdr;
  61.  
  62. HWAVEOUT    hWaveOut; 
  63.  
  64. WAVEOUTCAPS    wavecaps;
  65.  
  66. DWORD    gSndBufSize;
  67.  
  68. MMTIME        mmstarttime;
  69.  
  70. LPDIRECTSOUND pDS;
  71. LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
  72.  
  73. HINSTANCE hInstDS;
  74.  
  75. qboolean SNDDMA_InitDirect (void);
  76. qboolean SNDDMA_InitWav (void);
  77.  
  78. void FreeSound( void );
  79.  
  80. static const char *DSoundError( int error )
  81. {
  82.     switch ( error )
  83.     {
  84.     case DSERR_BUFFERLOST:
  85.         return "DSERR_BUFFERLOST";
  86.     case DSERR_INVALIDCALL:
  87.         return "DSERR_INVALIDCALLS";
  88.     case DSERR_INVALIDPARAM:
  89.         return "DSERR_INVALIDPARAM";
  90.     case DSERR_PRIOLEVELNEEDED:
  91.         return "DSERR_PRIOLEVELNEEDED";
  92.     }
  93.  
  94.     return "unknown";
  95. }
  96.  
  97. /*
  98. ** DS_CreateBuffers
  99. */
  100. static qboolean DS_CreateBuffers( void )
  101. {
  102.     DSBUFFERDESC    dsbuf;
  103.     DSBCAPS            dsbcaps;
  104.     WAVEFORMATEX    pformat, format;
  105.     DWORD            dwWrite;
  106.  
  107.     memset (&format, 0, sizeof(format));
  108.     format.wFormatTag = WAVE_FORMAT_PCM;
  109.     format.nChannels = dma.channels;
  110.     format.wBitsPerSample = dma.samplebits;
  111.     format.nSamplesPerSec = dma.speed;
  112.     format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
  113.     format.cbSize = 0;
  114.     format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign; 
  115.  
  116.     Com_Printf( "Creating DS buffers\n" );
  117.  
  118.     Com_DPrintf("...setting EXCLUSIVE coop level: " );
  119.     if ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_EXCLUSIVE ) )
  120.     {
  121.         Com_Printf ("failed\n");
  122.         FreeSound ();
  123.         return false;
  124.     }
  125.     Com_DPrintf("ok\n" );
  126.  
  127. // get access to the primary buffer, if possible, so we can set the
  128. // sound hardware format
  129.     memset (&dsbuf, 0, sizeof(dsbuf));
  130.     dsbuf.dwSize = sizeof(DSBUFFERDESC);
  131.     dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
  132.     dsbuf.dwBufferBytes = 0;
  133.     dsbuf.lpwfxFormat = NULL;
  134.  
  135.     memset(&dsbcaps, 0, sizeof(dsbcaps));
  136.     dsbcaps.dwSize = sizeof(dsbcaps);
  137.     primary_format_set = false;
  138.  
  139.     Com_DPrintf( "...creating primary buffer: " );
  140.     if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL))
  141.     {
  142.         pformat = format;
  143.  
  144.         Com_DPrintf( "ok\n" );
  145.         if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat))
  146.         {
  147.             if (snd_firsttime)
  148.                 Com_DPrintf ("...setting primary sound format: failed\n");
  149.         }
  150.         else
  151.         {
  152.             if (snd_firsttime)
  153.                 Com_DPrintf ("...setting primary sound format: ok\n");
  154.  
  155.             primary_format_set = true;
  156.         }
  157.     }
  158.     else
  159.         Com_Printf( "failed\n" );
  160.  
  161.     if ( !primary_format_set || !s_primary->value)
  162.     {
  163.     // create the secondary buffer we'll actually work with
  164.         memset (&dsbuf, 0, sizeof(dsbuf));
  165.         dsbuf.dwSize = sizeof(DSBUFFERDESC);
  166.         dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE;
  167.         dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
  168.         dsbuf.lpwfxFormat = &format;
  169.  
  170.         memset(&dsbcaps, 0, sizeof(dsbcaps));
  171.         dsbcaps.dwSize = sizeof(dsbcaps);
  172.  
  173.         Com_DPrintf( "...creating secondary buffer: " );
  174.         if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL))
  175.         {
  176.             Com_Printf( "failed\n" );
  177.             FreeSound ();
  178.             return false;
  179.         }
  180.         Com_DPrintf( "ok\n" );
  181.  
  182.         dma.channels = format.nChannels;
  183.         dma.samplebits = format.wBitsPerSample;
  184.         dma.speed = format.nSamplesPerSec;
  185.  
  186.         if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps))
  187.         {
  188.             Com_Printf ("*** GetCaps failed ***\n");
  189.             FreeSound ();
  190.             return false;
  191.         }
  192.  
  193.         Com_Printf ("...using secondary sound buffer\n");
  194.     }
  195.     else
  196.     {
  197.         Com_Printf( "...using primary buffer\n" );
  198.  
  199.         Com_DPrintf( "...setting WRITEPRIMARY coop level: " );
  200.         if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, cl_hwnd, DSSCL_WRITEPRIMARY))
  201.         {
  202.             Com_Printf( "failed\n" );
  203.             FreeSound ();
  204.             return false;
  205.         }
  206.         Com_DPrintf( "ok\n" );
  207.  
  208.         if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps))
  209.         {
  210.             Com_Printf ("*** GetCaps failed ***\n");
  211.             return false;
  212.         }
  213.  
  214.         pDSBuf = pDSPBuf;
  215.     }
  216.  
  217.     // Make sure mixer is active
  218.     pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
  219.  
  220.     if (snd_firsttime)
  221.         Com_Printf("   %d channel(s)\n"
  222.                        "   %d bits/sample\n"
  223.                        "   %d bytes/sec\n",
  224.                        dma.channels, dma.samplebits, dma.speed);
  225.     
  226.     gSndBufSize = dsbcaps.dwBufferBytes;
  227.  
  228.     /* we don't want anyone to access the buffer directly w/o locking it first. */
  229.     lpData = NULL; 
  230.  
  231.     pDSBuf->lpVtbl->Stop(pDSBuf);
  232.     pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite);
  233.     pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
  234.  
  235.     dma.samples = gSndBufSize/(dma.samplebits/8);
  236.     dma.samplepos = 0;
  237.     dma.submission_chunk = 1;
  238.     dma.buffer = (unsigned char *) lpData;
  239.     sample16 = (dma.samplebits/8) - 1;
  240.  
  241.     return true;
  242. }
  243.  
  244. /*
  245. ** DS_DestroyBuffers
  246. */
  247. static void DS_DestroyBuffers( void )
  248. {
  249.     Com_DPrintf( "Destroying DS buffers\n" );
  250.     if ( pDS )
  251.     {
  252.         Com_DPrintf( "...setting NORMAL coop level\n" );
  253.         pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_NORMAL );
  254.     }
  255.  
  256.     if ( pDSBuf )
  257.     {
  258.         Com_DPrintf( "...stopping and releasing sound buffer\n" );
  259.         pDSBuf->lpVtbl->Stop( pDSBuf );
  260.         pDSBuf->lpVtbl->Release( pDSBuf );
  261.     }
  262.  
  263.     // only release primary buffer if it's not also the mixing buffer we just released
  264.     if ( pDSPBuf && ( pDSBuf != pDSPBuf ) )
  265.     {
  266.         Com_DPrintf( "...releasing primary buffer\n" );
  267.         pDSPBuf->lpVtbl->Release( pDSPBuf );
  268.     }
  269.     pDSBuf = NULL;
  270.     pDSPBuf = NULL;
  271.  
  272.     dma.buffer = NULL;
  273. }
  274.  
  275. /*
  276. ==================
  277. FreeSound
  278. ==================
  279. */
  280. void FreeSound (void)
  281. {
  282.     int        i;
  283.  
  284.     Com_DPrintf( "Shutting down sound system\n" );
  285.  
  286.     if ( pDS )
  287.         DS_DestroyBuffers();
  288.  
  289.     if ( hWaveOut )
  290.     {
  291.         Com_DPrintf( "...resetting waveOut\n" );
  292.         waveOutReset (hWaveOut);
  293.  
  294.         if (lpWaveHdr)
  295.         {
  296.             Com_DPrintf( "...unpreparing headers\n" );
  297.             for (i=0 ; i< WAV_BUFFERS ; i++)
  298.                 waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR));
  299.         }
  300.  
  301.         Com_DPrintf( "...closing waveOut\n" );
  302.         waveOutClose (hWaveOut);
  303.  
  304.         if (hWaveHdr)
  305.         {
  306.             Com_DPrintf( "...freeing WAV header\n" );
  307.             GlobalUnlock(hWaveHdr);
  308.             GlobalFree(hWaveHdr);
  309.         }
  310.  
  311.         if (hData)
  312.         {
  313.             Com_DPrintf( "...freeing WAV buffer\n" );
  314.             GlobalUnlock(hData);
  315.             GlobalFree(hData);
  316.         }
  317.  
  318.     }
  319.  
  320.     if ( pDS )
  321.     {
  322.         Com_DPrintf( "...releasing DS object\n" );
  323.         pDS->lpVtbl->Release( pDS );
  324.     }
  325.  
  326.     if ( hInstDS )
  327.     {
  328.         Com_DPrintf( "...freeing DSOUND.DLL\n" );
  329.         FreeLibrary( hInstDS );
  330.         hInstDS = NULL;
  331.     }
  332.  
  333.     pDS = NULL;
  334.     pDSBuf = NULL;
  335.     pDSPBuf = NULL;
  336.     hWaveOut = 0;
  337.     hData = 0;
  338.     hWaveHdr = 0;
  339.     lpData = NULL;
  340.     lpWaveHdr = NULL;
  341.     dsound_init = false;
  342.     wav_init = false;
  343. }
  344.  
  345. /*
  346. ==================
  347. SNDDMA_InitDirect
  348.  
  349. Direct-Sound support
  350. ==================
  351. */
  352. sndinitstat SNDDMA_InitDirect (void)
  353. {
  354.     DSCAPS            dscaps;
  355.     HRESULT            hresult;
  356.  
  357.     dma.channels = 2;
  358.     dma.samplebits = 16;
  359.  
  360.     if (s_khz->value == 44)
  361.         dma.speed = 44100;
  362.     if (s_khz->value == 22)
  363.         dma.speed = 22050;
  364.     else
  365.         dma.speed = 11025;
  366.  
  367.     Com_Printf( "Initializing DirectSound\n");
  368.  
  369.     if ( !hInstDS )
  370.     {
  371.         Com_DPrintf( "...loading dsound.dll: " );
  372.  
  373.         hInstDS = LoadLibrary("dsound.dll");
  374.         
  375.         if (hInstDS == NULL)
  376.         {
  377.             Com_Printf ("failed\n");
  378.             return SIS_FAILURE;
  379.         }
  380.  
  381.         Com_DPrintf ("ok\n");
  382.         pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate");
  383.  
  384.         if (!pDirectSoundCreate)
  385.         {
  386.             Com_Printf ("*** couldn't get DS proc addr ***\n");
  387.             return SIS_FAILURE;
  388.         }
  389.     }
  390.  
  391.     Com_DPrintf( "...creating DS object: " );
  392.     while ( ( hresult = iDirectSoundCreate( NULL, &pDS, NULL ) ) != DS_OK )
  393.     {
  394.         if (hresult != DSERR_ALLOCATED)
  395.         {
  396.             Com_Printf( "failed\n" );
  397.             return SIS_FAILURE;
  398.         }
  399.  
  400.         if (MessageBox (NULL,
  401.                         "The sound hardware is in use by another app.\n\n"
  402.                         "Select Retry to try to start sound again or Cancel to run Quake with no sound.",
  403.                         "Sound not available",
  404.                         MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
  405.         {
  406.             Com_Printf ("failed, hardware already in use\n" );
  407.             return SIS_NOTAVAIL;
  408.         }
  409.     }
  410.     Com_DPrintf( "ok\n" );
  411.  
  412.     dscaps.dwSize = sizeof(dscaps);
  413.  
  414.     if ( DS_OK != pDS->lpVtbl->GetCaps( pDS, &dscaps ) )
  415.     {
  416.         Com_Printf ("*** couldn't get DS caps ***\n");
  417.     }
  418.  
  419.     if ( dscaps.dwFlags & DSCAPS_EMULDRIVER )
  420.     {
  421.         Com_DPrintf ("...no DSound driver found\n" );
  422.         FreeSound();
  423.         return SIS_FAILURE;
  424.     }
  425.  
  426.     if ( !DS_CreateBuffers() )
  427.         return SIS_FAILURE;
  428.  
  429.     dsound_init = true;
  430.  
  431.     Com_DPrintf("...completed successfully\n" );
  432.  
  433.     return SIS_SUCCESS;
  434. }
  435.  
  436.  
  437. /*
  438. ==================
  439. SNDDM_InitWav
  440.  
  441. Crappy windows multimedia base
  442. ==================
  443. */
  444. qboolean SNDDMA_InitWav (void)
  445. {
  446.     WAVEFORMATEX  format; 
  447.     int                i;
  448.     HRESULT            hr;
  449.  
  450.     Com_Printf( "Initializing wave sound\n" );
  451.     
  452.     snd_sent = 0;
  453.     snd_completed = 0;
  454.  
  455.     dma.channels = 2;
  456.     dma.samplebits = 16;
  457.  
  458.     if (s_khz->value == 44)
  459.         dma.speed = 44100;
  460.     if (s_khz->value == 22)
  461.         dma.speed = 22050;
  462.     else
  463.         dma.speed = 11025;
  464.  
  465.     memset (&format, 0, sizeof(format));
  466.     format.wFormatTag = WAVE_FORMAT_PCM;
  467.     format.nChannels = dma.channels;
  468.     format.wBitsPerSample = dma.samplebits;
  469.     format.nSamplesPerSec = dma.speed;
  470.     format.nBlockAlign = format.nChannels
  471.         *format.wBitsPerSample / 8;
  472.     format.cbSize = 0;
  473.     format.nAvgBytesPerSec = format.nSamplesPerSec
  474.         *format.nBlockAlign; 
  475.     
  476.     /* Open a waveform device for output using window callback. */ 
  477.     Com_DPrintf ("...opening waveform device: ");
  478.     while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, 
  479.                     &format, 
  480.                     0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR)
  481.     {
  482.         if (hr != MMSYSERR_ALLOCATED)
  483.         {
  484.             Com_Printf ("failed\n");
  485.             return false;
  486.         }
  487.  
  488.         if (MessageBox (NULL,
  489.                         "The sound hardware is in use by another app.\n\n"
  490.                         "Select Retry to try to start sound again or Cancel to run Quake 2 with no sound.",
  491.                         "Sound not available",
  492.                         MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
  493.         {
  494.             Com_Printf ("hw in use\n" );
  495.             return false;
  496.         }
  497.     } 
  498.     Com_DPrintf( "ok\n" );
  499.  
  500.     /* 
  501.      * Allocate and lock memory for the waveform data. The memory 
  502.      * for waveform data must be globally allocated with 
  503.      * GMEM_MOVEABLE and GMEM_SHARE flags. 
  504.  
  505.     */ 
  506.     Com_DPrintf ("...allocating waveform buffer: ");
  507.     gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
  508.     hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize); 
  509.     if (!hData) 
  510.     { 
  511.         Com_Printf( " failed\n" );
  512.         FreeSound ();
  513.         return false; 
  514.     }
  515.     Com_DPrintf( "ok\n" );
  516.  
  517.     Com_DPrintf ("...locking waveform buffer: ");
  518.     lpData = GlobalLock(hData);
  519.     if (!lpData)
  520.     { 
  521.         Com_Printf( " failed\n" );
  522.         FreeSound ();
  523.         return false; 
  524.     } 
  525.     memset (lpData, 0, gSndBufSize);
  526.     Com_DPrintf( "ok\n" );
  527.  
  528.     /* 
  529.      * Allocate and lock memory for the header. This memory must 
  530.      * also be globally allocated with GMEM_MOVEABLE and 
  531.      * GMEM_SHARE flags. 
  532.      */ 
  533.     Com_DPrintf ("...allocating waveform header: ");
  534.     hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, 
  535.         (DWORD) sizeof(WAVEHDR) * WAV_BUFFERS); 
  536.  
  537.     if (hWaveHdr == NULL)
  538.     { 
  539.         Com_Printf( "failed\n" );
  540.         FreeSound ();
  541.         return false; 
  542.     } 
  543.     Com_DPrintf( "ok\n" );
  544.  
  545.     Com_DPrintf ("...locking waveform header: ");
  546.     lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr); 
  547.  
  548.     if (lpWaveHdr == NULL)
  549.     { 
  550.         Com_Printf( "failed\n" );
  551.         FreeSound ();
  552.         return false; 
  553.     }
  554.     memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
  555.     Com_DPrintf( "ok\n" );
  556.  
  557.     /* After allocation, set up and prepare headers. */ 
  558.     Com_DPrintf ("...preparing headers: ");
  559.     for (i=0 ; i<WAV_BUFFERS ; i++)
  560.     {
  561.         lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE; 
  562.         lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE;
  563.  
  564.         if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) !=
  565.                 MMSYSERR_NOERROR)
  566.         {
  567.             Com_Printf ("failed\n");
  568.             FreeSound ();
  569.             return false;
  570.         }
  571.     }
  572.     Com_DPrintf ("ok\n");
  573.  
  574.     dma.samples = gSndBufSize/(dma.samplebits/8);
  575.     dma.samplepos = 0;
  576.     dma.submission_chunk = 512;
  577.     dma.buffer = (unsigned char *) lpData;
  578.     sample16 = (dma.samplebits/8) - 1;
  579.  
  580.     wav_init = true;
  581.  
  582.     return true;
  583. }
  584.  
  585. /*
  586. ==================
  587. SNDDMA_Init
  588.  
  589. Try to find a sound device to mix for.
  590. Returns false if nothing is found.
  591. ==================
  592. */
  593. int SNDDMA_Init(void)
  594. {
  595.     sndinitstat    stat;
  596.  
  597.     memset ((void *)&dma, 0, sizeof (dma));
  598.  
  599.     s_wavonly = Cvar_Get ("s_wavonly", "0", 0);
  600.  
  601.     dsound_init = wav_init = 0;
  602.  
  603.     stat = SIS_FAILURE;    // assume DirectSound won't initialize
  604.  
  605.     /* Init DirectSound */
  606.     if (!s_wavonly->value)
  607.     {
  608.         if (snd_firsttime || snd_isdirect)
  609.         {
  610.             stat = SNDDMA_InitDirect ();
  611.  
  612.             if (stat == SIS_SUCCESS)
  613.             {
  614.                 snd_isdirect = true;
  615.  
  616.                 if (snd_firsttime)
  617.                     Com_Printf ("dsound init succeeded\n" );
  618.             }
  619.             else
  620.             {
  621.                 snd_isdirect = false;
  622.                 Com_Printf ("*** dsound init failed ***\n");
  623.             }
  624.         }
  625.     }
  626.  
  627. // if DirectSound didn't succeed in initializing, try to initialize
  628. // waveOut sound, unless DirectSound failed because the hardware is
  629. // already allocated (in which case the user has already chosen not
  630. // to have sound)
  631.     if (!dsound_init && (stat != SIS_NOTAVAIL))
  632.     {
  633.         if (snd_firsttime || snd_iswave)
  634.         {
  635.  
  636.             snd_iswave = SNDDMA_InitWav ();
  637.  
  638.             if (snd_iswave)
  639.             {
  640.                 if (snd_firsttime)
  641.                     Com_Printf ("Wave sound init succeeded\n");
  642.             }
  643.             else
  644.             {
  645.                 Com_Printf ("Wave sound init failed\n");
  646.             }
  647.         }
  648.     }
  649.  
  650.     snd_firsttime = false;
  651.  
  652.     snd_buffer_count = 1;
  653.  
  654.     if (!dsound_init && !wav_init)
  655.     {
  656.         if (snd_firsttime)
  657.             Com_Printf ("*** No sound device initialized ***\n");
  658.  
  659.         return 0;
  660.     }
  661.  
  662.     return 1;
  663. }
  664.  
  665. /*
  666. ==============
  667. SNDDMA_GetDMAPos
  668.  
  669. return the current sample position (in mono samples read)
  670. inside the recirculating dma buffer, so the mixing code will know
  671. how many sample are required to fill it up.
  672. ===============
  673. */
  674. int SNDDMA_GetDMAPos(void)
  675. {
  676.     MMTIME    mmtime;
  677.     int        s;
  678.     DWORD    dwWrite;
  679.  
  680.     if (dsound_init) 
  681.     {
  682.         mmtime.wType = TIME_SAMPLES;
  683.         pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
  684.         s = mmtime.u.sample - mmstarttime.u.sample;
  685.     }
  686.     else if (wav_init)
  687.     {
  688.         s = snd_sent * WAV_BUFFER_SIZE;
  689.     }
  690.  
  691.  
  692.     s >>= sample16;
  693.  
  694.     s &= (dma.samples-1);
  695.  
  696.     return s;
  697. }
  698.  
  699. /*
  700. ==============
  701. SNDDMA_BeginPainting
  702.  
  703. Makes sure dma.buffer is valid
  704. ===============
  705. */
  706. DWORD    locksize;
  707. void SNDDMA_BeginPainting (void)
  708. {
  709.     int        reps;
  710.     DWORD    dwSize2;
  711.     DWORD    *pbuf, *pbuf2;
  712.     HRESULT    hresult;
  713.     DWORD    dwStatus;
  714.  
  715.     if (!pDSBuf)
  716.         return;
  717.  
  718.     // if the buffer was lost or stopped, restore it and/or restart it
  719.     if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK)
  720.         Com_Printf ("Couldn't get sound buffer status\n");
  721.     
  722.     if (dwStatus & DSBSTATUS_BUFFERLOST)
  723.         pDSBuf->lpVtbl->Restore (pDSBuf);
  724.     
  725.     if (!(dwStatus & DSBSTATUS_PLAYING))
  726.         pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
  727.  
  728.     // lock the dsound buffer
  729.  
  730.     reps = 0;
  731.     dma.buffer = NULL;
  732.  
  733.     while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &locksize, 
  734.                                    &pbuf2, &dwSize2, 0)) != DS_OK)
  735.     {
  736.         if (hresult != DSERR_BUFFERLOST)
  737.         {
  738.             Com_Printf( "S_TransferStereo16: Lock failed with error '%s'\n", DSoundError( hresult ) );
  739.             S_Shutdown ();
  740.             return;
  741.         }
  742.         else
  743.         {
  744.             pDSBuf->lpVtbl->Restore( pDSBuf );
  745.         }
  746.  
  747.         if (++reps > 2)
  748.             return;
  749.     }
  750.     dma.buffer = (unsigned char *)pbuf;
  751. }
  752.  
  753. /*
  754. ==============
  755. SNDDMA_Submit
  756.  
  757. Send sound to device if buffer isn't really the dma buffer
  758. Also unlocks the dsound buffer
  759. ===============
  760. */
  761. void SNDDMA_Submit(void)
  762. {
  763.     LPWAVEHDR    h;
  764.     int            wResult;
  765.  
  766.     if (!dma.buffer)
  767.         return;
  768.  
  769.     // unlock the dsound buffer
  770.     if (pDSBuf)
  771.         pDSBuf->lpVtbl->Unlock(pDSBuf, dma.buffer, locksize, NULL, 0);
  772.  
  773.     if (!wav_init)
  774.         return;
  775.  
  776.     //
  777.     // find which sound blocks have completed
  778.     //
  779.     while (1)
  780.     {
  781.         if ( snd_completed == snd_sent )
  782.         {
  783.             Com_DPrintf ("Sound overrun\n");
  784.             break;
  785.         }
  786.  
  787.         if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) )
  788.         {
  789.             break;
  790.         }
  791.  
  792.         snd_completed++;    // this buffer has been played
  793.     }
  794.  
  795. //Com_Printf ("completed %i\n", snd_completed);
  796.     //
  797.     // submit a few new sound blocks
  798.     //
  799.     while (((snd_sent - snd_completed) >> sample16) < 8)
  800.     {
  801.         h = lpWaveHdr + ( snd_sent&WAV_MASK );
  802.     if (paintedtime/256 <= snd_sent)
  803.         break;    //    Com_Printf ("submit overrun\n");
  804. //Com_Printf ("send %i\n", snd_sent);
  805.         snd_sent++;
  806.         /* 
  807.          * Now the data block can be sent to the output device. The 
  808.          * waveOutWrite function returns immediately and waveform 
  809.          * data is sent to the output device in the background. 
  810.          */ 
  811.         wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR)); 
  812.  
  813.         if (wResult != MMSYSERR_NOERROR)
  814.         { 
  815.             Com_Printf ("Failed to write block to device\n");
  816.             FreeSound ();
  817.             return; 
  818.         } 
  819.     }
  820. }
  821.  
  822. /*
  823. ==============
  824. SNDDMA_Shutdown
  825.  
  826. Reset the sound device for exiting
  827. ===============
  828. */
  829. void SNDDMA_Shutdown(void)
  830. {
  831.     FreeSound ();
  832. }
  833.  
  834.  
  835. /*
  836. ===========
  837. S_Activate
  838.  
  839. Called when the main window gains or loses focus.
  840. The window have been destroyed and recreated
  841. between a deactivate and an activate.
  842. ===========
  843. */
  844. void S_Activate (qboolean active)
  845. {
  846.     if ( active )
  847.     {
  848.         if ( pDS && cl_hwnd && snd_isdirect )
  849.         {
  850.             DS_CreateBuffers();
  851.         }
  852.     }
  853.     else
  854.     {
  855.         if ( pDS && cl_hwnd && snd_isdirect )
  856.         {
  857.             DS_DestroyBuffers();
  858.         }
  859.     }
  860. }
  861.  
  862.